package com.example.userserver.manager;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.userserver.domain.TokenDO;
import com.example.userserver.entity.UserInfo;
import com.example.userserver.mapper.UserInfoMapper;
import com.example.userserver.utils.Md5Utils;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.auth0.jwt.JWT;

import java.util.concurrent.TimeUnit;

@Service
public class AccountManage {
    private static final String TOKEN_KEY = "USER_TOKEN:%s";
    private static final String ID = "id";
    private static final String SESSION_ID = "session";

    @Value("${token.expire.minutes}")
    private Long tokenExpireMinutes;

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private RedissonClient redissonClient;

    public UserInfo getUserInfoByAccount(String account){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("account", account);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        return userInfo;
    }


    public void register(UserInfo userInfo) {
        userInfoMapper.insert(userInfo);
    }

    public boolean checkAccount(String account) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("account", account);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if(ObjectUtil.isNotNull(userInfo)){
            return true;
        }
        return false;
    }

    public boolean checkUserName(String userName) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_name", userName);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if(ObjectUtil.isNotNull(userInfo)){
            return true;
        }
        return false;
    }

    public String getNewToken(String userId) {
        String sessionId = Md5Utils.getRandom32Str();
        String newSecret = Md5Utils.getRandom32Str();
        Long expiration = System.currentTimeMillis() + tokenExpireMinutes;
        Algorithm algorithm = Algorithm.HMAC256(newSecret);
        String newToken = JWT.create().withClaim(ID, userId).withClaim(SESSION_ID, sessionId)
                .sign(algorithm);
        TokenDO tokenDO = new TokenDO();
        tokenDO.setUserId(userId);
        tokenDO.setToken(newToken);
        tokenDO.setStatus(0);
        tokenDO.setSecret(newSecret);
        RMapCache<String, TokenDO> tokenMap = redissonClient.getMapCache(String.format(TOKEN_KEY, userId));
        tokenMap.fastPut(sessionId, tokenDO, expiration, TimeUnit.MINUTES);
        return newToken;
    }


    /**验证Token的正确性*/
    public Boolean checkToken(String token) {
        try {
            TokenDO tokenDO = this.getUserToken(token);
            if (tokenDO == null) {
                return false;
            }
            if (!tokenDO.getStatus().equals(0)) {
                return false;
            }
            Algorithm algorithm = Algorithm.HMAC256(tokenDO.getSecret());
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
//            LOGGER.error("check token error token:{}", token, e);
        }
        return false;
    }

    public String getUserIdByToken(String token){
        DecodedJWT tokenInfo = JWT.decode(token);
        return tokenInfo.getClaim("userId").asString();
    }

    private TokenDO getUserToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        String id = this.getTokenID(token);
        if (id == null) {
            return null;
        }
        String sessionId = this.getTokenSessionId(token);
        if (StringUtils.isEmpty(sessionId)) {
            return null;
        }
        RMapCache<String, TokenDO> tokenMap = redissonClient.getMapCache(String.format(TOKEN_KEY, id));
        return tokenMap.get(sessionId);
    }

    /**获取token userId*/
    public String getTokenID(String token) {
        try {
            if (StringUtils.isEmpty(token) || "null".equals(token.toLowerCase())) {
                return null;
            }
            DecodedJWT decodedJWT = JWT.decode(token);
            Claim id = decodedJWT.getClaim(ID);
            if (id != null) {
                return id.asString();
            }
        } catch (Exception e) {
//            LOGGER.error("get token uuid error token:{}", token, e);
        }
        return null;
    }

    /**获取token session id*/
    public String getTokenSessionId(String token) {
        try {
            if (StringUtils.isEmpty(token) || "null".equals(token.toLowerCase())) {
                return null;
            }
            DecodedJWT decodedJWT = JWT.decode(token);
            Claim sessionId = decodedJWT.getClaim(SESSION_ID);
            if (sessionId != null) {
                return sessionId.asString();
            }
        } catch (Exception e) {
//            LOGGER.error("get token session id error token:{}", token, e);
        }
        return null;
    }

    public UserInfo getUserById(String id) {
        return userInfoMapper.selectById(id);
    }
}
